package com.mybatis.lo.config;

import com.mybatis.lo.constant.ExecutorType;
import com.mybatis.lo.executor.Executor;
import com.mybatis.lo.executor.SimpleExecutor;
import com.mybatis.lo.handler.DefaultParameterHandler;
import com.mybatis.lo.handler.DefaultResultSetHandler;
import com.mybatis.lo.handler.ParameterHandler;
import com.mybatis.lo.handler.ResultSetHandler;
import com.mybatis.lo.handler.RoutingStatementHandler;
import com.mybatis.lo.handler.StatementHandler;
import com.mybatis.lo.mapping.BoundSql;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.Setter;

import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;

/**
 * 负责记录`Mybatis`所有的配置信息；各种处理器（`Executor、ResultSetHandler、ParameterHandler`等）的策略产地
 * @author zhangbh
 * 2023-06-09 07:16
 **/
@Setter
public class Configuration {

    /**
     * 数据源对象
     */
    @Getter
    private DataSource dataSource;

    @Setter(AccessLevel.PRIVATE)
    private Map<String, MappedStatement> mappedStatements = new HashMap<>();

    /**
     * 是否开启二级缓存，占坑
     */
    private boolean enableCaching = true;
    /**
     * 默认的执行器类型
     */
    @Getter(AccessLevel.PUBLIC)
    protected ExecutorType defaultExecutorType = ExecutorType.SIMPLE;

    public MappedStatement getMappedStatement(String statementId) {
        return mappedStatements.get(statementId);
    }

    /**
     * 增加查询关联信息
     * @param statementId ID
     * @param mappedStatement 配置信息
     * @return 全局配置对象
     */
    public Configuration addMappedStatement(String statementId, MappedStatement mappedStatement) {
        mappedStatements.put(statementId, mappedStatement);
        return this;
    }

    /**
     * 创建一个执行器
     * @param executorType 执行器类型
     * @return 执行器
     */
    public Executor newExecutor(ExecutorType executorType) {
        if (executorType == null) {
            executorType = ExecutorType.SIMPLE;
        }
        // todo 可补充其他实现
        switch (executorType) {
            case SIMPLE:
                return new SimpleExecutor();
            case REUSE:
            case BATCH:
            default:
                throw new RuntimeException("未识别的执行器类型");
        }
    }

    public StatementHandler newStatementHandler(MappedStatement mappedStatement, BoundSql boundSql, Object param) {
        // 这边通过代理模式，如有变更则尽量少修改此类
        ParameterHandler parameterHandler = this.newParameterHandler(mappedStatement, boundSql, param);
        ResultSetHandler resultSetHandler = this.newResultSetHandler(mappedStatement, mappedStatement.getResultType());
        return new RoutingStatementHandler(mappedStatement, parameterHandler, resultSetHandler, boundSql, param);
    }

    private ParameterHandler newParameterHandler(MappedStatement mappedStatement, BoundSql boundSql, Object param) {
        return new DefaultParameterHandler(mappedStatement, boundSql, param);
    }

    private ResultSetHandler newResultSetHandler(MappedStatement mappedStatement, Class<?> resultType) {
        return new DefaultResultSetHandler(mappedStatement, resultType);
    }
}
